-
Notifications
You must be signed in to change notification settings - Fork 352
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extend the BorTag GC to AllocIds #3103
Conversation
@rustbot author |
intptrcast: remove information about dead allocations The discussion in #3103 convinced me we don't have to keep `int_to_ptr_map` around for dead allocations. But we should not make that depend on the GC, we can just tie it to when the allocation gets freed. That means everything still behaves deterministically, if anything weird happens (but it shouldn't). r? `@saethlin` Only the first and last commit contain logic changes, the 2nd commit just moves code around a bit.
☔ The latest upstream changes (presumably #3122) made this pull request unmergeable. Please resolve the merge conflicts. |
This isn't ready, I'm still thinking about your two comments I didn't mark as resolved. |
intptrcast: remove information about dead allocations The discussion in rust-lang/miri#3103 convinced me we don't have to keep `int_to_ptr_map` around for dead allocations. But we should not make that depend on the GC, we can just tie it to when the allocation gets freed. That means everything still behaves deterministically, if anything weird happens (but it shouldn't). r? `@saethlin` Only the first and last commit contain logic changes, the 2nd commit just moves code around a bit.
@rustbot author |
// live allocation IDs and all provenance in the allocation bytes, even if they are leaked. | ||
// Here we exploit that `adjust_allocation` always returns `Owned`, to all | ||
// tcx-managed allocations ever read or written will be copied in `alloc_map`. | ||
self.memory.alloc_map().iter(|it| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also have the secondary memory map in tcx
. I guess we have to walk that one as well, judging from the test failures. The comment I suggested about not having to worry about tcx-managed allocation seems to be wrong.
In particular it is wrong for function and vtable allocations, which never get copied into the local alloc_map
.
Co-authored-by: Ralf Jung <[email protected]>
Co-authored-by: Ralf Jung <[email protected]>
CI has been running for an hour. That's not good. I'll look into it. |
The slow part of the CI is inserting all the live AllocIds into the reachable set. Aside from asking the interpreter to track a The cde that's causing the GC to lose track of a pointer is here, and it has a wild diagnostic:
type GetEntropyFn = unsafe extern "C" fn(*mut u8, libc::size_t) -> libc::c_int;
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
static GETENTROPY: Weak = unsafe { Weak::new("getentropy\0") };
if let Some(fptr) = GETENTROPY.ptr() {
let func: GetEntropyFn = unsafe { mem::transmute(fptr) };
for chunk in dest.chunks_mut(256) {
let ret = unsafe { func(chunk.as_mut_ptr(), chunk.len()) }; |
That test? We run all tests on Linux with "do GC after every step". Lines 38 to 40 in d36c3e7
And that seems to be good, we caught a bug? For performance, here's one idea: we don't actually need the set. We need a function |
Ah, that's the old macOS getrandom doing strange integer pointer shenanigans. If this triggers a GC bug then the first thing to do is extract it into a dedicated test so that we don't have to rely on a pass-dep test to catch this. It should then also reproduce on all targets; the reason it's macOS-only is that getrandom uses different code for different targets. |
Here's a minimization: #![feature(rustc_private)]
extern crate libc;
extern "Rust" {
pub fn miri_run_provenance_gc();
}
type GetEntropyFn = unsafe extern "C" fn(*mut u8, libc::size_t) -> libc::c_int;
fn main() {
let name = "getentropy\0";
let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _) as usize };
unsafe {
miri_run_provenance_gc();
}
let ptr = addr as *mut libc::c_void;
let func: GetEntropyFn = unsafe { std::mem::transmute(ptr) };
let dest = &mut [0u8];
unsafe { func(dest.as_mut_ptr(), dest.len()) };
} Run with |
Lol that's not even right I forgot that the default is to run sparingly 🤦 |
Ah! I think the GC isn't picking up the contents of |
I think this is going to be easier to do as a rustc PR, so that I can iterate on the interface between Miri and the interpreter core code. I'll set up that later today. |
However, rustc doesn't run all tests with (We should probably rename that flag in this PR as well...) |
Aha! If we follow my proposal, the API we need is an efficient "is this AllocId live". So that's a single |
Subsumed by rust-lang/rust#118029 |
As suggested in #3080 (comment)
We previously solved memory growth issues associated with the Stacked Borrows and Tree Borrows runtimes with a GC. But of course we also have state accumulation associated with whole allocations elsewhere in the interpreter, and this PR starts tackling those.
To do this, we expand the visitor for the GC so that it can visit a BorTag or an AllocId. Then when the GC runs, we use the reachable set of AllocIds to remove elements from the intptrcast state.